#include "bsp.h"
#include <string.h>
#include "SW_SPI/sw_spi.h"

#define SW_SPI 0 // 软件SPI
#define HW_SPI 1 // 硬件SPI
#define SPI_TYPE HW_SPI

#if SPI_TYPE == HW_SPI
// 是否支持DMA
#define HW_SPI_SUPPORT_DMA 1
// 是否阻塞
#define HW_SPI_DMA_NOBLOCK 1
// 是否启用DMA 16bit
#define HW_SPI_DMA_16BIT 1

#endif

#define LCD_DEFAULT_WIDTH 240
#define LCD_DEFAULT_HEIGHT 280
uint16_t LCD_Width = LCD_DEFAULT_WIDTH;		// LCD 宽度
uint16_t LCD_Height = LCD_DEFAULT_HEIGHT;   // LCD 高度
uint8_t  LCD_Orientation = LCD_DISPLAY_ORIENTATION;// 默认纵向

#if SPI_TYPE == HW_SPI
#if HW_SPI_SUPPORT_DMA
uint8_t send_buff[2*LCD_DEFAULT_HEIGHT];
#endif
#endif

#define SPI_SCK_1()     LCD_ST7789_SCK_PORT->BSRR = LCD_ST7789_SCK_PIN
#define SPI_SCK_0()     LCD_ST7789_SCK_PORT->BSRR = LCD_ST7789_SCK_PIN << 16

#define SPI_SDO_1()     LCD_ST7789_MOSI_PORT->BSRR = LCD_ST7789_MOSI_PIN 
#define SPI_SDO_0()     LCD_ST7789_MOSI_PORT->BSRR = LCD_ST7789_MOSI_PIN << 16

#define SPI_CS_1()      LCD_ST7789_CS_PORT->BSRR = LCD_ST7789_CS_PIN 
#define SPI_CS_0()      LCD_ST7789_CS_PORT->BSRR = LCD_ST7789_CS_PIN << 16

#define SPI_SDI_READ()  0
// #define SPI_SDI_READ()  ((LCD_ST7789_MISO_PORT->IDR & LCD_ST7789_MISO_PIN) != 0) // 读取SDI引脚的值

#define LCD_DC_1()      LCD_ST7789_DC_PORT->BSRR = LCD_ST7789_DC_PIN 
#define LCD_DC_0()      LCD_ST7789_DC_PORT->BSRR = LCD_ST7789_DC_PIN << 16

#define LCD_RST_1()      LCD_ST7789_RST_PORT->BSRR = LCD_ST7789_RST_PIN 
#define LCD_RST_0()      LCD_ST7789_RST_PORT->BSRR = LCD_ST7789_RST_PIN << 16

#define LCD_BLK_1()      LCD_ST7789_BLK_PORT->BSRR = LCD_ST7789_BLK_PIN 
#define LCD_BLK_0()      LCD_ST7789_BLK_PORT->BSRR = LCD_ST7789_BLK_PIN << 16

#if SPI_TYPE == SW_SPI

static void SPI_SDO_LOW(void);
static void SPI_SDO_HIGH(void);
static void SPI_SCK_LOW(void);
static void SPI_SCK_HIGH(void);
static uint8_t SPI_SDI_READ_LEVEL(void);
static void SPI_CS_LOW(void);
static void SPI_CS_HIGH(void);
static void SPI_Delay(uint32_t us);



/* Private variables ---------------------------------------------------------*/
// 定义spi驱动对象
static sw_spi_dev_t spi_lcd_st7789_dev;
#define DATA_BUF_SIZE LCD_DEFAULT_WIDTH*LCD_DEFAULT_HEIGHT

#endif

/*The LCD needs a bunch of command/argument values to be initialized. They are stored in this struct. */
typedef struct {
    uint8_t cmd;
    uint8_t data[16];
    uint8_t databytes; //No of data in data; bit 7 = delay after set; 0xFF = end of cmds.
} lcd_init_cmd_t;




void bsp_lcd_hw_reset(void)
{
    LCD_RST_0();
    HAL_Delay_ms(100);
    LCD_RST_1();
    HAL_Delay_ms(100);
}

void bsp_lcd_wakeup(void)
{
    bsp_lcd_write_cmd(0x11); // 唤醒
    HAL_Delay_ms(120);
}

void bsp_lcd_backlight_on(void)
{
    LCD_BLK_1(); // 背光打开
}

void bsp_lcd_backlight_off(void)
{
    LCD_BLK_0(); // 背光关闭
}


void lcd_st7789_gpio_config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    /* 打开GPIO时钟 */
    RCC_AHB1PeriphClockCmd(RCC_LCD_ST7789_PORT, ENABLE);

#if SPI_TYPE == SW_SPI

    /* 设为输出口 */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;		
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  	 	

    GPIO_InitStructure.GPIO_Pin = LCD_ST7789_SCK_PIN;
    GPIO_Init(LCD_ST7789_SCK_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = LCD_ST7789_MOSI_PIN;
    GPIO_Init(LCD_ST7789_MOSI_PORT, &GPIO_InitStructure);

#elif SPI_TYPE == HW_SPI

    // 端口映射
    GPIO_PinAFConfig(LCD_ST7789_SCK_PORT, GPIO_PinSource3, GPIO_AF_SPI1); 
	GPIO_PinAFConfig(LCD_ST7789_MOSI_PORT, GPIO_PinSource5, GPIO_AF_SPI1); 

    /* 设为输出口 */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;		
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  	 	

    GPIO_InitStructure.GPIO_Pin = LCD_ST7789_SCK_PIN;
    GPIO_Init(LCD_ST7789_SCK_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = LCD_ST7789_MOSI_PIN;
    GPIO_Init(LCD_ST7789_MOSI_PORT, &GPIO_InitStructure);


#endif

    /* 设为输出口 */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;		
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;	 
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  

    GPIO_InitStructure.GPIO_Pin = LCD_ST7789_CS_PIN;
    GPIO_Init(LCD_ST7789_CS_PORT, &GPIO_InitStructure);
    // DC
    GPIO_InitStructure.GPIO_Pin = LCD_ST7789_DC_PIN;
    GPIO_Init(LCD_ST7789_DC_PORT, &GPIO_InitStructure);

    // RST
    GPIO_InitStructure.GPIO_Pin = LCD_ST7789_RST_PIN;
    GPIO_Init(LCD_ST7789_RST_PORT, &GPIO_InitStructure);

    // BLK
    GPIO_InitStructure.GPIO_Pin = LCD_ST7789_BLK_PIN;
    GPIO_Init(LCD_ST7789_BLK_PORT, &GPIO_InitStructure);

    SPI_CS_1(); // 
    LCD_DC_1(); // 写数据模式
    LCD_RST_1();
    bsp_lcd_backlight_off(); // 背光关

}

void lcd_st7789_spi_config(void)
{
#if SPI_TYPE == SW_SPI

    spi_lcd_st7789_dev.name = "spi_lcd_st7789";
    spi_lcd_st7789_dev.speed = 0;
    spi_lcd_st7789_dev.mode = SPI_MODE_3;
    spi_lcd_st7789_dev.bit_order = SPI_MSB_FIRST;
    spi_lcd_st7789_dev.delay_us = SPI_Delay;
    spi_lcd_st7789_dev.ops.sdo_low = SPI_SDO_LOW;
    spi_lcd_st7789_dev.ops.sdo_high = SPI_SDO_HIGH;
    spi_lcd_st7789_dev.ops.sck_low = SPI_SCK_LOW;
    spi_lcd_st7789_dev.ops.sck_high = SPI_SCK_HIGH;
    spi_lcd_st7789_dev.ops.sdi_read_level = SPI_SDI_READ_LEVEL;
    spi_lcd_st7789_dev.ops.cs_low = SPI_CS_LOW;
    spi_lcd_st7789_dev.ops.cs_high = SPI_CS_HIGH;
    sw_spi_init(&spi_lcd_st7789_dev);

#elif SPI_TYPE == HW_SPI
    SPI_InitTypeDef SPI_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);  // 开启SPI1时钟

    SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;           // 只发送
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                      // 主模式
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                  // 8位数据
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                         // CPOL=0
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;                       // CPHA=0（Mode 0）
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                          // 软件控制NSS
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; // 波特率分频（APB2时钟/4）
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                 // 高位先行
    SPI_InitStructure.SPI_CRCPolynomial = 7;                           // CRC多项式（默认值）
    SPI_Init(SPI1, &SPI_InitStructure);
    SPI_Cmd(SPI1, ENABLE);  // 使能SPI1


#if HW_SPI_SUPPORT_DMA
    DMA_InitTypeDef DMA_InitStruct;
    NVIC_InitTypeDef NVIC_InitStruct;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
    
    /* 复位初始化DMA数据流 */  
    DMA_DeInit(DMA2_Stream3);								
    /* 确保DMA数据流复位完成 */  
    while (DMA_GetCmdStatus(DMA2_Stream3) != DISABLE);	
    /* 配置 DMA Stream */
    DMA_InitStruct.DMA_Channel = DMA_Channel_2;                   // SPI1_TX对应Channel 2
    DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;  // 外设地址 SPI数据寄存器地址
    DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)0;             // 内存地址(要传输的变量的指针) ,DMA存储器0地址
    DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;          // 方向：存储器到外设
    DMA_InitStruct.DMA_BufferSize = 0;                            // 数据传输量 ,可设置为0， 实际发送时会重新设置
    DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设非增量模式
    DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;          // 存储器增量模式
#if HW_SPI_DMA_16BIT
    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 外设数据长度:16位
    DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;         // 存储器数据长度:16位
#else
    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 外设数据长度:16位
    DMA_InitStruct.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;         // 存储器数据长度:16位
#endif

    DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;                               // DMA模式：正常模式
    DMA_InitStruct.DMA_Priority = DMA_Priority_High;                 // 优先级：高
    DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;              // 禁用FIFO 
    DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
    DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;         // 外设突发单次传输
    DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; // 存储器突发单次传输
    DMA_Init(DMA2_Stream2, &DMA_InitStruct);
    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
#if HW_SPI_DMA_NOBLOCK

    // 配置中断（传输完成）
    NVIC_InitStruct.NVIC_IRQChannel = DMA2_Stream2_IRQn; // DMA发送中断源
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; // 抢占优先级
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2; // 子优先级
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; // 使能中断
    NVIC_Init(&NVIC_InitStruct);

    DMA_ITConfig(DMA2_Stream2, DMA_IT_TC, ENABLE); // 开启传输完成中断

#endif

#endif


#endif
}

#if SPI_TYPE == HW_SPI

#if HW_SPI_DMA_16BIT
void lcd_hw_spi_switch_txbits(uint8_t bits)
{
    uint16_t spiBitSet = 0;
    if(bits == 16) {
        spiBitSet = SPI_DataSize_16b;
    }
    else {
        spiBitSet = SPI_DataSize_8b;
    }
    SPI_Cmd(SPI1, DISABLE);          // 关闭SPI
    SPI_DataSizeConfig(SPI1, spiBitSet); // 设置数据位宽
    SPI_Cmd(SPI1, ENABLE);           // 开启SPI
}
#endif

uint8_t lcd_hw_spi_sendbyte(uint8_t byte)
{
#if 0
    // 双工 SPI_Direction_2Lines_FullDuplex
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // 等待发送缓冲区空
    SPI_I2S_SendData(SPI1, byte);                                   // 发送数据
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); // 等待接收完成（清空RX）
    SPI_I2S_ReceiveData(SPI1);                                      // 丢弃接收的数据
	return 0;
#endif
    // 只发送 
    SPI_I2S_SendData(SPI1, byte);                                   // 发送数据
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // 等待发送缓冲区空
}

#if HW_SPI_SUPPORT_DMA 
void lcd_hw_spi_send_dma(uint8_t *buffer, uint16_t size)
{
    // 等待DMA空闲
    while (DMA_GetCmdStatus(DMA2_Stream2) == ENABLE);
	// // 关闭发送 DMA		
	// DMA_Cmd(DMA2_Stream2, DISABLE);	
    // 配置DMA源地址和长度
    DMA_SetCurrDataCounter(DMA2_Stream2, size);
    DMA_MemoryTargetConfig(DMA2_Stream2, (uint32_t)buffer, DMA_Memory_0);
    // 启动DMA传输
    DMA_Cmd(DMA2_Stream2, ENABLE);
#if HW_SPI_DMA_NOBLOCK
    // 非阻塞

#else
    // 阻塞等待传输完成
    while (DMA_GetFlagStatus(DMA2_Stream2, DMA_FLAG_TCIF2) == RESET);
    // 清理标志位并关闭DMA
    DMA_ClearFlag(DMA2_Stream2, DMA_FLAG_TCIF2);
    DMA_Cmd(DMA2_Stream2, DISABLE);


#endif
}
#endif

#endif


void lcd_st7789_config(void)
{
    int cmd = 0;
    lcd_init_cmd_t ili_init_cmds[]={
        {0x3A, {0x05}, 1}, // 像素点格式
        {0xB2, {0x0C, 0x0C, 0x00, 0x33, 0x33}, 5}, 
        {0xB7, {0x35}, 1},
        {0xBB, {0x19}, 1},
        {0xC0, {0x2C}, 1}, 
        {0xC2, {0x01}, 1}, 
        {0xC3, {0x12}, 1},         
        {0xC4, {0x20}, 1},      
        {0xC6, {0x0F}, 1}, 
        {0xD0, {0xA4, 0xA1}, 2},      
        {0xE0, {0xD0, 0x04, 0x0D, 0x11, 0x13, 0x2B, 0x3F, 0x54, 0x4C, 0x18, 0x0D, 0x0B, 0x1F, 0x23}, 14},     
        {0xE1, {0xD0, 0x04, 0x0C, 0x11, 0x13, 0x2C, 0x3F, 0x44, 0x51, 0x2F, 0x1F, 0x1F, 0x20, 0x23}, 14},	
        {0, {0}, 0xff},
    };

    bsp_lcd_hw_reset(); // 硬复位
    bsp_lcd_wakeup(); 
    bsp_lcd_set_orientation(LCD_DISPLAY_ORIENTATION);

	// 循环发送设置所有寄存器
	while (ili_init_cmds[cmd].databytes!=0xff) {
		bsp_lcd_write_cmd(ili_init_cmds[cmd].cmd);
		bsp_lcd_write_multidata(ili_init_cmds[cmd].data, ili_init_cmds[cmd].databytes & 0x1F);
		if (ili_init_cmds[cmd].databytes & 0x80) {
			// HAL_Delay_ms(100);
		}
		cmd++;
	}

    bsp_lcd_write_cmd(0x21); // 颜色反相
    bsp_lcd_write_cmd(0x29); // 显示启动
}


void bsp_lcd_st7789_init(void)
{
    
    // GPIO初始化
    lcd_st7789_gpio_config();
    // SPI初始化
    lcd_st7789_spi_config();
    // 配置初始化
    lcd_st7789_config();
    // 刷屏 
    // 初始化显示ic后屏幕会花屏，需要先刷完一帧数据后再打开背光
    bsp_lcd_clear(0x0000);

}

void bsp_lcd_st7789_refresh_test(void)
{
    for(;;)
    {
        bsp_lcd_clear(0xFFFF);

        bsp_lcd_clear(0x0000);

    }
}



void bsp_lcd_write_cmd(uint8_t cmd)
{
#if SPI_TYPE == SW_SPI
    uint8_t data_buf[1];
    sw_spi_msg_t sw_i2c_msg;
#endif
    LCD_DC_0(); // 写命令

#if SPI_TYPE == SW_SPI
    sw_i2c_msg.buf = data_buf;
    sw_i2c_msg.buf[0] = cmd;
    sw_i2c_msg.len = 1;
    sw_spi_transfer(&spi_lcd_st7789_dev, &sw_i2c_msg);    
#elif SPI_TYPE == HW_SPI
    SPI_CS_0();
    lcd_hw_spi_sendbyte(cmd);
    SPI_CS_1();
#endif 
    LCD_DC_1(); // 写数据

}

void bsp_lcd_write_data(uint8_t data)
{
#if SPI_TYPE == SW_SPI
    uint8_t data_buf[1];
    sw_spi_msg_t sw_i2c_msg;
    sw_i2c_msg.buf = data_buf;
    sw_i2c_msg.buf[0] = data;
    sw_i2c_msg.len = 1;
    sw_spi_transfer(&spi_lcd_st7789_dev, &sw_i2c_msg);    
#elif SPI_TYPE == HW_SPI
    SPI_CS_0();
    lcd_hw_spi_sendbyte(data);
    SPI_CS_1();
#endif
}



void bsp_lcd_write_multidata(uint8_t *pData, uint32_t len) 
{
    if(pData == NULL || len <= 0) 
        return;
#if SPI_TYPE == SW_SPI
    // uint8_t data_buf[DATA_BUF_SIZE];
    sw_spi_msg_t sw_i2c_msg;
    sw_i2c_msg.buf = pData;
    // memcpy(sw_i2c_msg.buf, pData, len);
    sw_i2c_msg.len = len;
    sw_spi_transfer(&spi_lcd_st7789_dev, &sw_i2c_msg);    
#elif SPI_TYPE == HW_SPI
    SPI_CS_0();

// #if HW_SPI_SUPPORT_DMA == 0
    for (uint32_t i = 0; i < len; i++) {
        lcd_hw_spi_sendbyte(pData[i]);
    }
// #else
//     lcd_hw_spi_send_dma(pData, len);
// #endif

// #if HW_SPI_SUPPORT_DMA && HW_SPI_DMA_NOBLOCK
// #else
    SPI_CS_1();
// #endif

#endif
    
}

void bsp_lcd_write_data_16bit(uint16_t _ucData)
{
    uint8_t data_buf[2] = {0,0};
    data_buf[0] = (_ucData >> 8) & 0xFF;
    data_buf[1] = _ucData & 0xFF;
    bsp_lcd_write_multidata(data_buf , 2);
    // LCD_WriteData(_ucData >> 8);
    // LCD_WriteData(_ucData);
}

#define OFFSET_PIXEL 20
// 设置LCD窗口函数
void bsp_lcd_setwindows(uint16_t Start_X, uint16_t Start_Y,uint16_t End_X,uint16_t End_Y)
{	
	if(LCD_Orientation == LCD_DISPLAY_ORIENTATION_PORTRAIT || LCD_Orientation == LCD_DISPLAY_ORIENTATION_PORTRAIT_INVERTED){
        bsp_lcd_write_cmd(0x2A);
        bsp_lcd_write_data_16bit(Start_X);
        bsp_lcd_write_data_16bit(End_X);
        bsp_lcd_write_cmd(0x2B);
        bsp_lcd_write_data_16bit(Start_Y+OFFSET_PIXEL);
        bsp_lcd_write_data_16bit(End_Y+OFFSET_PIXEL);	
    }
    else if(LCD_Orientation == LCD_DISPLAY_ORIENTATION_LANDSCAPE || LCD_Orientation == LCD_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED){
        bsp_lcd_write_cmd(0x2A);
        bsp_lcd_write_data_16bit(Start_X+OFFSET_PIXEL);
        bsp_lcd_write_data_16bit(End_X+OFFSET_PIXEL);
        bsp_lcd_write_cmd(0x2B);
        bsp_lcd_write_data_16bit(Start_Y);
        bsp_lcd_write_data_16bit(End_Y);
    }
    bsp_lcd_write_cmd(0x2C);		
}   



// 清屏
void bsp_lcd_clear(uint16_t Color)
{
  uint16_t x,y;  
	bsp_lcd_setwindows(0, 0, LCD_Width - 1, LCD_Height - 1);   
#if SPI_TYPE == SW_SPI
    spi_lcd_st7789_dev.ops.cs_low(); // 拉低片选信号
	for(x = 0; x < LCD_Height ; x++){
		for(y = 0 ; y < LCD_Width ; y++){	
            sw_spi_transfer_byte(&spi_lcd_st7789_dev, Color>>8);
            sw_spi_transfer_byte(&spi_lcd_st7789_dev, Color);
		}
	}
    spi_lcd_st7789_dev.ops.cs_high(); // 拉低片选信号
#elif SPI_TYPE == HW_SPI
    SPI_CS_0();
// #if HW_SPI_SUPPORT_DMA == 0
	for(x = 0; x < LCD_Height ; x++){
		for(y = 0 ; y < LCD_Width ; y++){	
            lcd_hw_spi_sendbyte(Color>>8);
            lcd_hw_spi_sendbyte(Color);
		}
	}
// #else 
//     for(y = 0 ; y < 2*LCD_Width ;) {
//         send_buff[y] = Color>>8;
//         send_buff[y+1] = Color;
//         y += 2;
//     }
// 	for(x = 0; x < LCD_Height ; x++){
//         lcd_hw_spi_send_dma(send_buff, 2*LCD_Width);
//     }
// #endif

// #if HW_SPI_SUPPORT_DMA && HW_SPI_DMA_NOBLOCK
// #else
    SPI_CS_1();
// #endif

#endif
} 
/**
 * @brief 填充屏幕区域
 * 
 * @param sX 起始 X 坐标
 * @param sY 起始 Y 坐标
 * @param eX 结束 X 坐标
 * @param eY 结束 Y 坐标
 * @param Color 填充颜色
 */
void bsp_lcd_fill(uint16_t Start_X, uint16_t Start_Y, uint16_t End_X, uint16_t End_Y, uint16_t Color)
{
    uint16_t x,y;  
    uint16_t width = End_X - Start_X + 1;
    uint16_t height = End_Y - Start_Y + 1;

    bsp_lcd_setwindows(Start_X, Start_Y, End_X, End_Y);
#if SPI_TYPE == SW_SPI
    spi_lcd_st7789_dev.ops.cs_low(); // 拉低片选信号
	for(x = 0; x < height ; x++){
		for(y = 0 ; y < width ; y++){	
            sw_spi_transfer_byte(&spi_lcd_st7789_dev, (Color>>8));
            sw_spi_transfer_byte(&spi_lcd_st7789_dev, Color);
		}
	}
    spi_lcd_st7789_dev.ops.cs_high(); // 拉低片选信号
#elif SPI_TYPE == HW_SPI
    SPI_CS_0();
#if HW_SPI_SUPPORT_DMA == 0
	for(x = 0; x < height ; x++){
		for(y = 0 ; y < width ; y++){	
            lcd_hw_spi_sendbyte(Color>>8);
            lcd_hw_spi_sendbyte(Color);
		}
	}
#else 

	for(x = 0; x < height ; x++){
        for(y = 0 ; y < width ; y++) {
            send_buff[2*y] = Color>>8;
            send_buff[2*y+1] = Color;
            y += 2;
        }
        lcd_hw_spi_send_dma(send_buff, 2*LCD_Width);
    }
#endif

#if HW_SPI_SUPPORT_DMA && HW_SPI_DMA_NOBLOCK
#else
    SPI_CS_1();
#endif

#endif

    
}

void bsp_lcd_fill_color(uint16_t Start_X, uint16_t Start_Y, uint16_t End_X, uint16_t End_Y, uint16_t *Color)
{
    uint16_t x,y;  
    uint16_t width = End_X - Start_X + 1;
    uint16_t height = End_Y - Start_Y + 1;

    bsp_lcd_setwindows(Start_X, Start_Y, End_X, End_Y);
#if SPI_TYPE == SW_SPI
    sw_spi_msg_t sw_i2c_msg;
    sw_i2c_msg.buf = (uint8_t *)Color;
    sw_i2c_msg.len = 2*height*width;
    sw_spi_transfer(&spi_lcd_st7789_dev, &sw_i2c_msg);    
#elif SPI_TYPE == HW_SPI
    SPI_CS_0();
#if HW_SPI_SUPPORT_DMA == 0
    bsp_lcd_write_multidata((u8 *)Color, 2*height*width);
#else 

#if HW_SPI_DMA_16BIT
    lcd_hw_spi_switch_txbits(16);
    lcd_hw_spi_send_dma((u8 *)Color, height*width);
#if HW_SPI_DMA_NOBLOCK == 0 
    lcd_hw_spi_switch_txbits(8);
#endif
#else
    lcd_hw_spi_send_dma((u8 *)Color, 2*height*width);
#endif

#endif

#if HW_SPI_SUPPORT_DMA && HW_SPI_DMA_NOBLOCK
#else
    SPI_CS_1();
#endif

#endif
}

// 设置屏幕方向
void bsp_lcd_set_orientation(uint8_t orientation)
{
	// const char *orientation_str[] = {"PORTRAIT", "PORTRAIT_INVERTED", "LANDSCAPE", "LANDSCAPE_INVERTED"};
	uint8_t data[] = {0x00, 0xC0, 0x70, 0xA0};
	//(1<<3)|(0<<6)|(0<<7));		// BGR==1,MY==0,MX==0,MV==0
	//(1<<3)|(0<<7)|(1<<6)|(1<<5));	// BGR==1,MY==1,MX==0,MV==1
	//(1<<3)|(1<<6)|(1<<7));		// BGR==1,MY==0,MX==0,MV==0
	//(1<<3)|(1<<7)|(1<<5));		// BGR==1,MY==1,MX==0,MV==1
	LCD_Orientation = orientation;
	if(orientation == LCD_DISPLAY_ORIENTATION_PORTRAIT || orientation == LCD_DISPLAY_ORIENTATION_PORTRAIT_INVERTED){
		LCD_Width = LCD_DEFAULT_WIDTH;		// LCD 宽度
		LCD_Height = LCD_DEFAULT_HEIGHT;		// LCD 高度
	}else if(orientation == LCD_DISPLAY_ORIENTATION_LANDSCAPE || orientation == LCD_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED){
		LCD_Width = LCD_DEFAULT_HEIGHT;		// LCD 宽度
		LCD_Height = LCD_DEFAULT_WIDTH;		// LCD 高度
	}

	bsp_lcd_write_cmd(0x36);
	bsp_lcd_write_multidata((void *) &data[orientation], 1);
}

#if SPI_TYPE == SW_SPI

static void SPI_SDO_LOW(void)
{
    SPI_SDO_0();
}

static void SPI_SDO_HIGH(void)
{
    SPI_SDO_1();
}

static void SPI_SCK_LOW(void)
{
    SPI_SCK_0();
}

static void SPI_SCK_HIGH(void)
{
    SPI_SCK_1();
}

static uint8_t SPI_SDI_READ_LEVEL(void)
{
    return SPI_SDI_READ();
}

static void SPI_CS_LOW(void)
{
    SPI_CS_0();
}
static void SPI_CS_HIGH(void)
{
    SPI_CS_1();
}



static void SPI_Delay(uint32_t us)
{
    HAL_Delay_us(us);
}


#endif

#if SPI_TYPE == HW_SPI
#if HW_SPI_SUPPORT_DMA && HW_SPI_DMA_NOBLOCK

extern void lv_port_disp_call_back(void);

void DMA2_Stream2_IRQHandler(void)
{
    if(DMA_GetITStatus(DMA2_Stream2, DMA_IT_TCIF2))
    {
        DMA_Cmd(DMA2_Stream2, DISABLE);
        // 片选拉高
        SPI_CS_1();

        lv_port_disp_call_back();
#if HW_SPI_DMA_NOBLOCK && HW_SPI_DMA_16BIT
        lcd_hw_spi_switch_txbits(8);
#endif
        // 清理标志位并关闭DMA
        DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TCIF2); 

    }
}

#endif
#endif




